home *** CD-ROM | disk | FTP | other *** search
/ The Arsenal Files 8 / The Arsenal Files Collection #8 (Arsenal Computer) (1996).ISO / g_quake / dxf2tri.zip / DXF2TRI.C < prev    next >
C/C++ Source or Header  |  1993-08-10  |  11KB  |  413 lines

  1. /*----------------------------------------------------------------------
  2.  
  3.                  DXF2TRI
  4.         DXF polyline/polygon to triangle converter
  5.              by Tim Riley   Aug 1993
  6.                 based on
  7.         POLY2TRI - a polygon to triangle converter
  8.              by Steve Anger Jan 1993
  9.  
  10. This program is commited to the public domain. Feel free to use all or part
  11. of this code in your own programs.
  12.  
  13. This is a utility that extracts polyline shapes from a DXF file and breaks
  14. them down into individual triangles. The polylines are assumed to be closed,
  15. planar (2D) polygons. This program only deals with POLYLINE entities and
  16. ignores all other entities in the DXF file. All properties (color, line type)
  17. are ignored. 
  18.  
  19. The input DXF file consists of one or more polylines with no more than 2000
  20. vertices. This limit is rather arbitrary and can be changed if necessary (by
  21. changing POLYMAX).
  22.  
  23. The program uses the following syntax:
  24.     DXF2TRI infile[.DXF] [outfile[.RAW]] [-e] [-b]
  25. with two options:
  26.     -e:    extrude the object one unit in the z direction (use SCALE
  27.         in the scene descriptor file to modify this). The extrusion
  28.         is only applied to the edge of the object, not to the in-
  29.         dividual triangles.
  30.     -b:    generate a back to the extruded object. This is useful if
  31.         the back will be visible (ex: in a reflection). This option
  32.         can be used without the -e option for whatever reason.
  33.  
  34. The output file consists of one triangle per line in the following format:
  35.                       x1 y1 z1 x2 y2 z2 x3 y3 z3
  36. and can be fed directly into RAW2POV to create an INC file with calculated
  37. bounding shapes (which speeds up tracing) and a POV file which gives limits
  38. of the total object to aid in positioning. RAW2POV converts some triangles
  39. (the extrusions) to smooth traingles, which gives a nice look to the sides.
  40.  
  41. NOTE:    the resultant object is a shell, not a solid, so take this into
  42.     account when applying textures, particularly wood and marble. Also,
  43.     the object won't work with CSG.
  44.  
  45. -----------------------------------------------------------------------*/
  46.  
  47. #include <math.h>
  48. #include <stdio.h>
  49. #include <stdlib.h>
  50. #include <string.h>
  51.  
  52. typedef struct {
  53.     float x, y, z;
  54. } Vector;
  55.  
  56. int remove_triangle (Vector *poly, int *polysize, Vector *v1, Vector *v2, Vector *v3);
  57. int poly_inside (Vector *poly, int polysize, Vector *v);
  58. void vect_init (Vector *v, float x, float y, float z);
  59. void vect_copy (Vector *v1, Vector *v2);
  60. void vect_add (Vector *v1, Vector *v2, Vector *v3);
  61. void vect_sub (Vector *v1, Vector *v2, Vector *v3);
  62. void vect_scale (Vector *v, float k);
  63. float vect_mag (Vector *v);
  64. float dot_prod (Vector *v1, Vector *v2);
  65. void cross_prod (Vector *v1, Vector *v2, Vector *v3);
  66. float vect_angle (Vector *v1, Vector *v2);
  67. void add_ext (char *fname, char *ext, int force);
  68. void pr_error (void);
  69. void option (char *string, int *extrude, int *back);
  70.  
  71. #define POLYMAX 2000
  72.  
  73. int main (int argc, char *argv[])
  74. {
  75.     FILE *fp_in, *fp_out;
  76.     char ch, infile[20] = "", outfile[20] = "", string[80];
  77.     int polysize, i, extrude = 0, back = 0;
  78.     float temp1, temp2;
  79.     Vector v[POLYMAX], v1, v2, v3;
  80.  
  81.     if (argc < 2) pr_error ();
  82.  
  83.     strcpy (infile, argv[1]);
  84.  
  85.     if (argc == 2) {
  86.     strcpy (outfile, infile);
  87.     add_ext (outfile, "raw", 1);
  88.     }
  89.     else {
  90.     strcpy (string, argv[2]);
  91.     if (string[0] != '-') strcpy (outfile, string);
  92.     else {
  93.         strcpy (outfile, infile);
  94.         add_ext (outfile, "raw", 1);
  95.         option (string, &extrude, &back);
  96.     }
  97.  
  98.     if (argc == 4) {
  99.         strcpy (string, argv[3]);
  100.         option (string, &extrude, &back);
  101.     }
  102.     if (argc == 5) {
  103.         strcpy (string, argv[4]);
  104.         option (string, &extrude, &back);
  105.     }
  106.     }
  107.  
  108.     add_ext (infile, "dxf", 0);
  109.     add_ext (outfile, "raw", 0);
  110.  
  111.     if ((fp_in=fopen(infile,"r")) == NULL) {
  112.         printf ("Cannot open input file '%s'\n", infile);
  113.         exit (EXIT_FAILURE);
  114.     }
  115.  
  116.     if ((fp_out=fopen(outfile,"w")) == NULL) {
  117.         printf ("Cannot open output file '%s'\n", outfile);
  118.         exit (EXIT_FAILURE);
  119.     }
  120.     do {
  121.         fscanf (fp_in, "%s", &string);
  122.     } while (strcmp (string, "ENTITIES") != 0);
  123.  
  124.     while (1) {
  125.         do {
  126.             fscanf (fp_in, "%s", &string);
  127.         } while (strcmp (string, "POLYLINE") != 0 &&
  128.              strcmp (string, "ENDSEC") != 0);
  129.         if (strcmp (string, "ENDSEC") == 0) break;
  130.  
  131.         polysize = 0;
  132.         while (1) {
  133.             do {
  134.                 fscanf (fp_in, "%s", &string);
  135.             } while (strcmp (string, "VERTEX") != 0 &&
  136.                  strcmp (string, "SEQEND") != 0);
  137.             if (strcmp (string, "SEQEND") == 0) break;
  138.             do {
  139.                 fscanf (fp_in, "%f", &temp1);
  140.                 fscanf (fp_in, "%f", &temp2);
  141.             } while (temp1 != 10);
  142.             v[polysize].x = temp2;
  143.             do {
  144.                 fscanf (fp_in, "%f", &temp1);
  145.                 fscanf (fp_in, "%f", &temp2);
  146.             } while (temp1 != 20);
  147.             v[polysize].y = temp2;
  148.             v[polysize++].z = 0.0;
  149.                 if (polysize >= POLYMAX) {
  150.                 printf ("Too many vertices. Break up into smaller sections & try again.\n");
  151.                 fclose (fp_in);
  152.                 fclose (fp_out);
  153.                 exit (1);
  154.               }
  155.  
  156.         }
  157.         /* Extrude 1 unit deep along the z axis */
  158.         if (extrude == 1) {
  159.             for (i=0; i<polysize; i++) {
  160.                 if (i<polysize-1) {
  161.                         fprintf (fp_out, "%f %f %f %f %f %f %f %f %f \n",
  162.                          v[i].x, v[i].y, v[i].z,
  163.                          v[i+1].x, v[i+1].y, v[i+1].z,
  164.                          v[i+1].x, v[i+1].y, v[i+1].z+1);
  165.                     fprintf (fp_out, "%f %f %f %f %f %f %f %f %f \n",
  166.                          v[i].x, v[i].y, v[i].z,
  167.                          v[i+1].x, v[i+1].y, v[i+1].z+1,
  168.                          v[i].x, v[i].y, v[i].z+1);
  169.                 }
  170.                 else {
  171.                     fprintf (fp_out, "%f %f %f %f %f %f %f %f %f \n",
  172.                          v[i].x, v[i].y, v[i].z,
  173.                          v[0].x, v[0].y, v[0].z,
  174.                          v[0].x, v[0].y, v[0].z+1);
  175.                     fprintf (fp_out, "%f %f %f %f %f %f %f %f %f \n",
  176.                          v[i].x, v[i].y, v[i].z,
  177.                          v[0].x, v[0].y, v[0].z+1,
  178.                          v[i].x, v[i].y, v[i].z+1);
  179.                 }
  180.             }
  181.         }
  182.  
  183.         /* Remove triangles from the polygon until there's nothing left */
  184.         while (remove_triangle (v, &polysize, &v1, &v2, &v3)) {
  185.             fprintf (fp_out, "%f %f %f %f %f %f %f %f %f \n",
  186.                  v1.x, v1.y, v1.z, v2.x, v2.y, v2.z, v3.x, v3.y, v3.z);
  187.             if (back == 1)
  188.                 fprintf (fp_out, "%f %f %f %f %f %f %f %f %f \n",
  189.                  v1.x, v1.y, v1.z+1.0, v2.x, v2.y, v2.z+1.0, v3.x, v3.y, v3.z+1.0);
  190.         }
  191.     }
  192.     fclose (fp_in);
  193.     fclose (fp_out);
  194.     return 0;
  195. }
  196.  
  197. void pr_error ()
  198. {
  199.     printf ("Usage: infile[.dxf] [outfile[.raw]] [-e] [-b]\n");
  200.     printf ("Where: -e: extrude the objects to a depth of 1.0\n");
  201.     printf ("       -b: include a back to the object\n");
  202.     exit (1);
  203. }
  204.  
  205. void option (char *string, int *extrude, int *back)
  206. {
  207.     if (string[0] != '-') pr_error();
  208.     if (string[1] == 'e' || string[1] == 'E') *extrude =1;
  209.     if (string[1] == 'b' || string[1] == 'B') *back =1;
  210. }
  211.  
  212. /* Removes a triangle from the specified polygon. */
  213. /* The size of the polygon is reduced */
  214. int remove_triangle (Vector *poly, int *polysize,
  215.              Vector *v1, Vector *v2, Vector *v3)
  216. {
  217.     Vector tri[3], center;
  218.     int    i, j, a, b, c;
  219.  
  220.     if (*polysize < 3)
  221.     return 0; /* No triangle found */
  222.  
  223.     /* This simplest case */
  224.     if (*polysize == 3) {
  225.     vect_copy (v1, &poly[0]);
  226.     vect_copy (v2, &poly[1]);
  227.     vect_copy (v3, &poly[2]);
  228.  
  229.     *polysize = 0;
  230.  
  231.     return 1;  /* Ok */
  232.     }
  233.  
  234.     for (i = 0; i < *polysize; i++) {
  235.     a = i;
  236.     b = (i + 1) % *polysize;
  237.     c = (i + 2) % *polysize;
  238.  
  239.     /* Select a candidate triangle */
  240.     vect_copy (&tri[0], &poly[a]);
  241.     vect_copy (&tri[1], &poly[b]);
  242.     vect_copy (&tri[2], &poly[c]);
  243.  
  244.     /* Calculate the center of the triangle */
  245.     vect_init (¢er, 0.0, 0.0, 0.0);
  246.     vect_add (¢er, ¢er, &tri[0]);
  247.     vect_add (¢er, ¢er, &tri[1]);
  248.     vect_add (¢er, ¢er, &tri[2]);
  249.     vect_scale (¢er, 1.0/3.0);
  250.  
  251.     /* Is the center of the triangle inside the original polygon? */
  252.     /* If not skip this triangle */
  253.     if (!poly_inside (poly, *polysize, ¢er))
  254.         continue;
  255.  
  256.     /* Are any of the polygons other vertices inside the triangle */
  257.     /* If so skip this triangle */
  258.     for (j = 0; j < *polysize; j++) {
  259.         if (j != a && j != b && j != c && poly_inside (tri, 3, &poly[j]))
  260.         break;
  261.     }
  262.  
  263.     if (j < *polysize)
  264.         continue;
  265.  
  266.     /* This is the one */
  267.     vect_copy (v1, &tri[0]);
  268.     vect_copy (v2, &tri[1]);
  269.     vect_copy (v3, &tri[2]);
  270.  
  271.     /* Remove this triangle from the polygon */
  272.     (*polysize)--;
  273.     for (j = b; j < *polysize; j++)
  274.         vect_copy (&poly[j], &poly[j+1]);
  275.  
  276.     return 1; /* Ok */
  277.     }
  278.  
  279.     return 0; /* No triangle found */
  280. }
  281.  
  282.  
  283. /* Determines if the specified point 'v' is inside the polygon. */
  284. /* Uses a convoluted version of the sum of angles approach */
  285. int poly_inside (Vector *poly, int polysize, Vector *v)
  286. {
  287.     Vector sum, cross, v1, v2;
  288.     float  magcross;
  289.     int    i;
  290.  
  291.     vect_init (&sum, 0.0, 0.0, 0.0);
  292.  
  293.     for (i = 0; i < polysize; i++) {
  294.     vect_sub (&v1, v, &poly[i]);
  295.     vect_sub (&v2, v, &poly[(i+1) % polysize]);
  296.  
  297.     cross_prod (&cross, &v1, &v2);
  298.     magcross = vect_mag (&cross);
  299.  
  300.     if (magcross > 0.0)
  301.         vect_scale (&cross, 1.0/magcross);
  302.  
  303.     vect_scale (&cross, vect_angle (&v1, &v2));
  304.     vect_add (&sum, &sum, &cross);
  305.     }
  306.  
  307.     return (vect_mag (&sum) > M_PI);
  308. }
  309.  
  310.  
  311. void vect_init (Vector *v, float  x, float  y, float  z)
  312. {
  313.     v->x = x;
  314.     v->y = y;
  315.     v->z = z;
  316. }
  317.  
  318.  
  319. void vect_copy (Vector *v1, Vector *v2)
  320. {
  321.     v1->x = v2->x;
  322.     v1->y = v2->y;
  323.     v1->z = v2->z;
  324. }
  325.  
  326.  
  327. void vect_add (Vector *v1, Vector *v2, Vector *v3)
  328. {
  329.     v1->x = v2->x + v3->x;
  330.     v1->y = v2->y + v3->y;
  331.     v1->z = v2->z + v3->z;
  332. }
  333.  
  334.  
  335. void vect_sub (Vector *v1, Vector *v2, Vector *v3)
  336. {
  337.     v1->x = v2->x - v3->x;
  338.     v1->y = v2->y - v3->y;
  339.     v1->z = v2->z - v3->z;
  340. }
  341.  
  342.  
  343. void vect_scale (Vector *v, float  k)
  344. {
  345.     v->x = k * v->x;
  346.     v->y = k * v->y;
  347.     v->z = k * v->z;
  348. }
  349.  
  350.  
  351. float vect_mag (Vector *v)
  352. {
  353.     float mag;
  354.     if (v->x==0.0 && v->y==0.0 && v->z==0.0) return 0.0;
  355.     mag = sqrt(v->x*v->x + v->y*v->y + v->z*v->z);
  356.  
  357.     return mag;
  358. }
  359.  
  360.  
  361. float dot_prod (Vector *v1, Vector *v2)
  362. {
  363.     return (v1->x*v2->x + v1->y*v2->y + v1->z*v2->z);
  364. }
  365.  
  366.  
  367. void cross_prod (Vector *v1, Vector *v2, Vector *v3)
  368. {
  369.     v1->x = (v2->y * v3->z) - (v2->z * v3->y);
  370.     v1->y = (v2->z * v3->x) - (v2->x * v3->z);
  371.     v1->z = (v2->x * v3->y) - (v2->y * v3->x);
  372. }
  373.  
  374.  
  375. /* Return the angle (rads) between two vectors */
  376. float vect_angle (Vector *v1, Vector *v2)
  377. {
  378.     float  mag1, mag2, angle, cos_theta;
  379.  
  380.     mag1 = vect_mag(v1);
  381.     mag2 = vect_mag(v2);
  382.  
  383.     if (mag1 * mag2 == 0.0)
  384.     angle = 0.0;
  385.     else {
  386.     cos_theta = dot_prod(v1,v2) / (mag1 * mag2);
  387.  
  388.     if (cos_theta <= -1.0)
  389.         angle = M_PI;
  390.     else if (cos_theta >= +1.0)
  391.         angle = 0.0;
  392.     else
  393.         angle = acos(cos_theta);
  394.     }
  395.  
  396.     return angle;
  397. }
  398.  
  399. void add_ext (char *fname, char *ext, int force)
  400. {
  401.     int i;
  402.  
  403.     for (i = 0; i < strlen (fname); i++)
  404.     if (fname[i] == '.') break;
  405.  
  406.     if (fname[i] == '\0' || force) {
  407.     if (strlen (ext) > 0)
  408.         fname[i++] = '.';
  409.  
  410.     strcpy (&fname[i], ext);
  411.     }
  412. }
  413.